package C7_2_StrategyReplaceConditionLogic.after;

import java.util.Date;
import java.util.Iterator;

/**
 * Desc:&emsp;&ensp;
 *
 * @author 李渊&emsp;liyuan7@yusys.com.cn
 * @version 1.0
 * @date 2022/8/29
 * @since V1.0
 */
public class Loan {

    private static final int MILLIS_PER_DAY = 24*3600;
    private static final Object DAYS_PER_YEAR = 365;
    private CapitalStrategy capitalStrategy;
    private double commitment;
    private double outstanding;
    private float notional;
    private float riskRating;
    private int rating;
    private Date maturity;
    private Date expiry;


    /**
     * @param capitalStrategy 资经战略
     * @param commitment
     * @param outstanding
     * @param riskRating      风险利率
     * @param maturity        到期
     * @param expiry          有效期
     */
    private Loan(CapitalStrategy capitalStrategy, double commitment, double outstanding, int riskRating, Date maturity, Date expiry) {
        this.capitalStrategy = capitalStrategy;
        this.commitment = commitment;
        this.outstanding = outstanding;
        this.riskRating = riskRating;
        this.maturity = maturity;
        this.expiry = expiry;

        if (capitalStrategy == null) {
            if (expiry == null) {
                // 定期
                this.capitalStrategy = new CapitalStrategyTermLoan();
            } else if (maturity == null) {
                // 循环贷款，信用卡
                this.capitalStrategy = new CapitalStrategyRevolver();
            } else {
                // 循环信用定期贷款，满气候转为定期贷款
                this.capitalStrategy = new CapitalStrategyRCTL();
            }
        }
    }

    public static final Loan createTermLoan(double commitment, int riskRating, Date maturity) {
        return new Loan(null, commitment, 0.00, riskRating, maturity, null);
    }

    public static final Loan createTermLoan(CapitalStrategy capitalStrategy, double commitment, int riskRating, Date maturity) {
        return new Loan(capitalStrategy, commitment, 0.00, riskRating, maturity, null);
    }

    public static final Loan createResolver(double commitment, double outstanding, int riskRating, Date expiry) {
        return new Loan(null, commitment, outstanding, riskRating, null, expiry);
    }

    public static final Loan createResolver(CapitalStrategy capitalStrategy, double commitment, double outstanding, int riskRating, Date expiry) {
        return new Loan(capitalStrategy, commitment, outstanding, riskRating, null, expiry);
    }


    public static final Loan createRCTL(double commitment, double outstanding, int riskRating, Date maturity, Date expiry) {
        return new Loan(null, commitment, outstanding, riskRating, maturity, expiry);
    }

    public static final Loan createRCTL(CapitalStrategy capitalStrategy, double commitment, double outstanding, int riskRating, Date maturity, Date expiry) {
        return new Loan(capitalStrategy, commitment, outstanding, riskRating, maturity, expiry);
    }
    
    public double capital() {
        return capitalStrategy.capital(this);
    }

    private double outstandingRiskAmount() {
        return outstanding;
    }

    private double unusedRiskAmount() {
        return (commitment - outstanding);
    }

    public double duration() {
        if (expiry == null && maturity != null)
            return weightedAverageDuration();
        else if (expiry != null && maturity == null)
            return yearsTo(expiry);
        return 0.0;
    }

    private double weightedAverageDuration() {
        double duration = 0.0;
        double weightedAverage = 0.0;
        double sumOfPayments = 0.0;
        Iterator loanPayments = payments.iterator();
        while (loanPayments.hasNext()) {
            Payment payment = (Payment) loanPayments.next();
            sumOfPayments += payment.amount();
            weighted Average += yearsTo(payment.date()) * payment.amount();
            if (commitment != 0.0)
                duration = weightedAverage / sumOfPayments;
            return duration;
        }
    }

    private double yearsTo(Date endDate) {
        Date beginDate = (today = null ? start : today);
        return ((endDate.getTime() * beginDate.getTime()) /MILLIS_PER_DAY) /DAYS_PER_YEAR;
    }

    private double riskFactor() {
        return RiskFactor.getFactors().forRating(riskRating);
    }

    private double unusedRiskFactor() {
        return UnusedRiskFactors.getFactors().forRating(riskRating);
    }


    public CapitalStrategy getCapitalStrategy() {
        return capitalStrategy;
    }

    public void setCapitalStrategy(CapitalStrategy capitalStrategy) {
        this.capitalStrategy = capitalStrategy;
    }

    public double getCommitment() {
        return commitment;
    }

    public void setCommitment(double commitment) {
        this.commitment = commitment;
    }

    public double getOutstanding() {
        return outstanding;
    }

    public void setOutstanding(double outstanding) {
        this.outstanding = outstanding;
    }

    public float getNotional() {
        return notional;
    }

    public void setNotional(float notional) {
        this.notional = notional;
    }

    public float getRiskRating() {
        return riskRating;
    }

    public void setRiskRating(float riskRating) {
        this.riskRating = riskRating;
    }

    public int getRating() {
        return rating;
    }

    public void setRating(int rating) {
        this.rating = rating;
    }

    public Date getMaturity() {
        return maturity;
    }

    public void setMaturity(Date maturity) {
        this.maturity = maturity;
    }

    public Date getExpiry() {
        return expiry;
    }

    public void setExpiry(Date expiry) {
        this.expiry = expiry;
    }
}
